package cate.game.pvp.eliterace.handler;

import cate.game.pvp.eliterace.data.EliteRaceRecord;
import cate.game.pvp.eliterace.data.EliteRaceRecordData;
import cate.game.pvp.eliterace.data.EliteRaceSpec;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

public class BothEliteRaceRecordOperation implements EliteRaceRecordOperation {

    private final EliteRaceRecordData recordData;

    public BothEliteRaceRecordOperation(Supplier<EliteRaceRecordData> recordDataSupplier) {
        this.recordData = Objects.requireNonNull(recordDataSupplier.get());
    }

    @Override
    public List<EliteRaceRecord> query(EliteRaceSpec spec) {
        EliteRaceSpec param = EliteRaceSpec.of(
                spec.getSeason(),
                spec.getPeriod(),
                spec.getGroup(),
                spec.getRound());
        Map<String, EliteRaceRecord> reportMap = recordData.getIndex(param.toString());
        return !CollectionUtils.isEmpty(reportMap)
                ? Lists.newArrayList(reportMap.values())
                : Lists.newArrayList();
    }

    @Override
    public List<EliteRaceRecord> query(EliteRaceSpec from, EliteRaceSpec to) {
        if (Objects.isNull(to)) {
            return null;
        }

        Predicate<? super EliteRaceRecord> predicate = Objects.isNull(from) ?
                (rd) -> {
                    EliteRaceSpec spec = rd.getSpec();
                    return spec.getPeriod() == to.getPeriod() && spec.getRound() == to.getRound();
                } :
                (rd) -> {
                    EliteRaceSpec spec = rd.getSpec();
                    return Objects.compare(spec, from, EliteRaceSpec::compareTo) >= 0
                            && Objects.compare(to, spec, EliteRaceSpec::compareTo) >= 0;
                };

        return recordData.getValueList().stream()
                .filter(predicate)
                .collect(Collectors.toList());
    }

    @Override
    public List<EliteRaceRecord> query(String uid, EliteRaceSpec from, EliteRaceSpec to) {
        if (Objects.isNull(to)) {
            return null;
        }

        Predicate<? super EliteRaceRecord> predicate = Objects.isNull(from) ?
                (rd) -> {
                    EliteRaceSpec spec = rd.getSpec();
                    return spec.getPeriod() == to.getPeriod() && spec.getRound() == to.getRound();
                } :
                (rd) -> {
                    EliteRaceSpec spec = rd.getSpec();
                    return Objects.compare(spec, from, EliteRaceSpec::compareTo) >= 0
                            && Objects.compare(to, spec, EliteRaceSpec::compareTo) >= 0;
                };

        return recordData.getValueList().stream()
                .filter(rd -> {
                    if (rd.getSpec().getPeriod() == 1) {
                        return StringUtils.equalsIgnoreCase(rd.getIdA(), uid);
                    } else {
                        return StringUtils.equalsIgnoreCase(rd.getIdA(), uid)
                                || StringUtils.equalsIgnoreCase(rd.getIdB(), uid);
                    }
                })
                .filter(predicate)
                .collect(Collectors.toList());
    }

    @Override
    public void addRecord(EliteRaceRecord record) {
        if (!recordData.contains(record.getSpec().toString(), record.getIndexName())) {
            recordData.addValue(record);
            recordData.addIndex(record.getSpec().toString(), record.getIndexName(), record);
        }
    }
}
